Cell diagnostics#980
Conversation
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
|
@vezwork @juliasilge I'm not sure who would be the best person to review this. It is big (although ~half is tests and test infra) so I'm happy to walk either/both of you through it in a call. |
If a user opens One eventual (but rapidly coming) goal of ark is that diagnostics on But if you were to open, say, So if you create That may not be exactly how ark works today, but we are rapidly iterating our way towards this kind of design |
|
Tested locally and I am getting red and blue underlines in R and Python cells in VSCode, and red and blue underlines in Python cells in Positron. |
this wasn't doing anything since the diagnostics for vdocs are handled by external language clients - not ours
Replace the deferred-promise/withVirtualDocUri architecture with independent DiagnosticSession objects — one per language per document. Each session manages its own vdoc lifecycle and timeout, so a non-responsive language server for one language doesn't block or interfere with another language's diagnostics. - Delete resource-map.ts (no longer needed) - Add optional timeoutMs constructor param (defaults to 10s) - Sessions merge diagnostics across languages when publishing - Add diagnostics-multilang.qmd test fixture - Update test language client to handle R documents - Add multi-language test verifying independent per-language diagnostics
…f separate function
The test language server is spawned as a child process by the LanguageClient, so it can't be part of the esbuild bundle. Converting it to plain JS means it never goes through the bundler and can be referenced directly from source.
53a28a6 to
eb288f5
Compare
|
rebased on main, updated changelog, and force pushed (excuse me, didn't mean to add myself as author to all these commits :|) |
juliasilge
left a comment
There was a problem hiding this comment.
This is working remarkably well as I put it through its paces:
I am really impressed. 😅
I will say that in the long run for Positron, I am still going to advocate that we take a different approach. I think an in-memory representation of .qmd that is very, very notebook-like will be a better option, both for LSP features as well as AI features. I am actually so eager for us to do that work as outlined in posit-dev/positron#12837 that I would advocate we do that instead of making the Ark LSP work with this new approach in this PR. That new document model approach also sets us up for the LSP work that @DavisVaughan mentions that would be truly difficult/impossible with vdoc files.
That being said, it is incredible to me that this works and I think we should merge it, pending some of the minor feedback on the PR. This would be a really huge win for VS Code (i.e. not Positron) users.
Co-authored-by: Elliot <key.draw@gmail.com>
Co-authored-by: Elliot <key.draw@gmail.com>
…om vdoc to document Previously only range, message, and severity were carried over. Now the full diagnostic is preserved, including rewriting relatedInformation URIs that point at the vdoc back to the source .qmd document.
If a document change causes sessions to be recreated while activateSession is awaiting virtualDocUriFromTempFile, the resumed continuation would mutate an orphaned session. Check that the session is still current before proceeding.
|
@DavisVaughan with this approach we can create the vdoc temp files next to the |
When a document closes before its async vdoc activation finishes,
disposeActiveVdoc would find session.activeVdoc still undefined and
skip disposal — causing the session-removed event to never fire.
Add a deferred promise (activated/resolveActivated) to each session.
activateSession resolves it in finally{}, and disposeActiveVdoc awaits
it unconditionally so activeVdoc is always set before disposal runs.
The "Can open a non-qmd file normally" test fails intermittently in CI because it uses assert.equal for editor reference identity. Under xvfb on Linux runners, VS Code may replace the editor instance during async operations while still showing the same document. The test's intent is to verify the extension doesn't steal focus from non-qmd files, so checking the active document URI is the correct assertion. Also await the edit and save calls that were previously fire-and-forget.
|
@vezwork @juliasilge I fixed a few more edge cases and CI is passing reliably (reran a few times and only failures were in other tests). Could you please take another look? |
juliasilge
left a comment
There was a problem hiding this comment.
This continues to work well for me in Positron, for both R and Python:
syntax-errors-working.mov
I'm excited to see how this approach plays out for users and definitely think we should merge/release this, although like I said before, I am also interested in us pursuing an option that avoids vdoc files on disk altogether, for Positron.
Fixes #208, joint work with @vezwork, building on #957. Here's how it works as described in the original PR:
We improved on that by creating vdocs in the temp dir when possible (pyrefly and ark) to keep it out of the user's workspace, and by deleting the vdoc once diagnostics are received.
The vscode-R extension is an exception and requires vdocs in the workspace, so we put it under
.quarto.Here's the full sequence diagram:
sequenceDiagram actor User participant VSC as VS Code participant Mgr as EmbeddedDiagnosticsManager<br/>(Quarto extension) participant LC as LanguageClient<br/>(vscode-languageclient) participant LS as Language Server<br/>(e.g. Pyrefly, Ark) User->>Mgr: User action initiates diagnostic request<br/>e.g. document open or edit (after debounce) activate Mgr Mgr->>Mgr: Parse and group cells by language loop For each language found in the document create participant VDoc as Virtual Document<br/>(temp file on disk) Mgr->>VDoc: Create temp file with code<br/>per language Mgr->>VSC: openTextDocument(vdoc URI) deactivate Mgr activate VSC VSC->>LC: onDidOpenTextDocument(vdoc) deactivate VSC activate LC LC->>LS: textDocument/didOpen (vdoc) deactivate LC activate LS LS-->>LS: Analyze document LS->>LC: textDocument/publishDiagnostics deactivate LS activate LC LC->>VSC: Set diagnostics for vdoc URI deactivate LC activate VSC VSC-->>User: ⚠️ Vdoc entry briefly visible<br/>in Problems pane (known issue) VSC->>Mgr: onDidChangeDiagnostics(vdoc URI) deactivate VSC activate Mgr par Publish .qmd cell diagnostics Mgr->>Mgr: Filter diagnostics to code cell ranges Mgr->>VSC: Set diagnostics for .qmd URI activate VSC VSC->>User: Squiggly underlines in editor +<br/>entries in Problems pane deactivate VSC and Cleanup Mgr->>VSC: Set vdoc language to plaintext activate VSC destroy VDoc Mgr-xVDoc: Delete temp file deactivate Mgr VSC->>LC: onDidCloseTextDocument(vdoc) deactivate VSC activate LC LC->>LS: textDocument/didClose deactivate LC activate LS LS->>LC: textDocument/publishDiagnostics (empty) deactivate LS activate LC LC->>VSC: Clear diagnostics for vdoc URI deactivate LC activate VSC VSC-->>User: Vdoc entry removed from Problems pane deactivate VSC end endClearing vdoc diagnostics
This also includes a fix to get vdoc diagnostics to actually clear. The problem is that VS Code constrains extensions' ability to close text documents and fire
onDidCloseTextDocument, which language clients forward to language servers astextDocument/didClosenotifications, and which they generally respond to by clearing diagnostics.One option was to use
WorkspaceEditto delete the file which would fire the event, but it doesn't let us skip the trash.The hack in this PR is to change the vdoc's language (set it to
plaintext), which sendstextDocument/didCloseand clears vdoc diagnostics.Known issues
Tests
There is an extensive e2e test suite included. It uses a fake language server, but otherwise exercises the full production code paths, and covers a bunch of edge cases that I ran into while working on this.
There's a bunch of test infra added that might be useful for testing the other language features in future.